package com.lk.mall.config;

import com.lk.mall.config.handler.TokenToAdminUserMethodArgumentResolver;
import com.lk.mall.config.handler.TokenToMallUserMethodArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author Lemonade
 * @description
 * @updateTime 2022/9/1 17:51
 */
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurationSupport {

    @Resource
    private TokenToMallUserMethodArgumentResolver tokenToMallUserMethodArgumentResolver;
    @Autowired
    private TokenToAdminUserMethodArgumentResolver tokenToAdminUserMethodArgumentResolver;

    /**
     * @param argumentResolvers 参数
     * @tip @TokenToMallUser @TokenToAdminUser 注解处理方法
     */
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(tokenToMallUserMethodArgumentResolver);
        argumentResolvers.add(tokenToAdminUserMethodArgumentResolver);
    }

    /**
     * @description
     * @author Lemonade
     * @param registry 跨域处理
     * @updateTime 2022/9/7 17:48
     */
    /**
     1, 所谓 CORS>
     CORS设置跨域不生效排查之路：https://blog.csdn.net/qq_34339137/article/details/111195894
     CORS(跨域资源共享)，通过设置 http 响应头来允许不同协议、ip、port可以跨域请求。

     2, 如何失效
     在springboot中，一般常采用两种方式实现CORS。
     （1）通过拦截器的方式，继承 WebMvcConfigurationSupport，重写addCorsMappings(CorsRegistry registry)方法

     protected void addCorsMappings(CorsRegistry registry) {
         registry.addMapping("/**")
         .allowCredentials(true)
         .allowedHeaders("*")
         .allowedMethods("*")
         .allowedOrigins("*");
         super.addCorsMappings(registry);
     }
    （2）通过过滤器的方式
     @Configuration
     public class GlobalCorsConfig {
        @Bean
        public CorsFilter corsFilter() {
            CorsConfiguration config = new CorsConfiguration();

            //开放哪些ip、端口、域名的访问权限，星号表示开放所有域
            config.addAllowedOrigin("*");

            //是否允许发送Cookie信息
            config.setAllowCredentials(true);

            //开放哪些Http方法，允许跨域访问
            config.addAllowedMethod("GET","POST", "PUT", "DELETE");

            //允许HTTP请求中携带哪些Header信息
            config.addAllowedHeader("*");

            //添加映射路径，“/**”表示对所有的路径实行全局跨域访问权限的设置
            UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
            configSource.registerCorsConfiguration("/**", config);
            return new CorsFilter(configSource);
        }
    }
     3, 可能存在的失效情况
     (1)
     存在多个 WebMvcConfigurationSupport 或者 WebMvcConfigurerAdapter，可能会导致设置的允许跨域 addCorsMappings不生效。
     存在多个自定义的拦截器，执行顺序导致设置跨域失效。（跨域拦截器应在业务拦截器前执行！）
     (2)
     过滤器是先于拦截器执行的，所以使用过滤器不用考虑到和拦截器冲突的问题。（过滤器设置CORS允许跨域请求，拦截器处理业务代码）
     过滤器的时候，设置了 response 的响应头允许跨域，但到了拦截器的时候，又把 response 重置了，导致设置的不生效。

     4, 总结一下
     建议使用过滤器的方式（先于拦截器执行）
     解决跨域还有其他的多种方案（推荐采用代理 nginx、网关方式）
     */

    @Override
    protected void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true).maxAge(3600);
    }


    // 配置拦截器
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/upload/**").addResourceLocations("file:" + "D:\\upload\\");
        registry.addResourceHandler("/goods-img/**").addResourceLocations("file:" + "D:\\upload\\");

        registry.
                addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
                .resourceChain(false);

        // 解决 No mapping for GET /doc.html 的问题
        // 参考：https://blog.csdn.net/weixin_45081945/article/details/126562542
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}
